package matheus.tp01cg.objetosdedesenho.recorte;

import matheus.tp01cg.objetosdedesenho.Coords;
import matheus.tp01cg.objetosdedesenho.Reta;
import android.util.Log;

/**
 * Recorte de retas utilizadno CohenSutherland
 * 
 * @author matheus
 * 
 */
public class CohenSutherland extends Recorte {

	public CohenSutherland(Coords limMin, Coords limMax) {
		super(limMin, limMax);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * matheus.tp01cg.objetosdedesenho.recorte.Recorte#recortaReta(matheus.tp01cg
	 * .objetosdedesenho.Reta)
	 */
	@Override
	protected Reta recortaReta(Reta reta) {
		Reta retorno = null;
		try {
			retorno = (Reta) reta.clone();
			boolean aceite = false;
			boolean feito = false;
			short cod1, cod2, cfora;
			int x1, y1, x2, y2;
			Coords intersecao = new Coords(0, 0);
			while (!feito) {
				x1 = retorno.getPontoInicial().x;
				y1 = retorno.getPontoInicial().y;
				x2 = retorno.getPontoFinal().x;
				y2 = retorno.getPontoFinal().y;
				cod1 = regionCode(retorno.getPontoInicial());
				cod2 = regionCode(retorno.getPontoFinal());
				if (cod1 == 0 && cod2 == 0) {
					// segmento completamente dentro
					aceite = true;
					feito = true;
				} else if ((cod1 & cod2) != 0) {
					// segmento completamente fora
					feito = true;
				} else {
					if (cod1 != 0) {
						// determina um ponto exterior
						cfora = cod1;
					} else {
						cfora = cod2;
					}
					if ((cfora & 0x01) == 0x01) { // bit 0
						// limite esquerdo
						intersecao.x = limMin.x;
						intersecao.y = y1 + (y2 - y1) * (limMin.x - x1)
								/ (x2 - x1);
					} else if ((cfora & 0x02) == 0x02) { // bit 1
						// limite direito
						intersecao.x = limMax.x;
						intersecao.y = y1 + (y2 - y1) * (limMax.x - x1)
								/ (x2 - x1);
					} else if ((cfora & 0x04) == 0x04) { // bit 2
						// limite abaixo
						intersecao.y = limMin.y;
						intersecao.x = x1 + (x2 - x1) * (limMin.y - y1)
								/ (y2 - y1);
					} else if ((cfora & 0x08) == 0x08) { // bit 3
						// limite acima
						intersecao.y = limMax.y;
						intersecao.x = x1 + (x2 - x1) * (limMax.y - y1)
								/ (y2 - y1);
					}
					if (cod1 == cfora) {
						retorno.getPontoInicial().x = intersecao.x;
						retorno.getPontoInicial().y = intersecao.y;
					} else {
						retorno.getPontoFinal().x = intersecao.x;
						retorno.getPontoFinal().y = intersecao.y;
					}
				}
			}
			if (!aceite) {
				retorno.nula = true;
			}
		} catch (Exception e) {
			Log.d(null, null, e);
		}
		return retorno;
	}

	private short regionCode(Coords ponto) {
		short cod = 0;
		// esquerda - bit 0
		if (ponto.x < limMin.x) {
			cod += 1;
		}
		// direita - bit 1
		if (ponto.x > limMax.x) {
			cod += 2;
		}
		// baixo - bit 2
		if (ponto.y < limMin.y) {
			cod += 4;
		}
		// cima - bit 3
		if (ponto.y > limMax.y) {
			cod += 8;
		}
		return cod;
	}
}
